/**
 * @file sline.h
 * @author zhuxuanlin (xuanlinzhu@qq.com)
 * @brief sline命令行组件的功能实现
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#ifndef __SLINE_H__
#define __SLINE_H__

#ifdef __cplusplus
extern "C" {
#endif

#include "ck_config.h"
// /* 环境是否为LS2K1000 */
// #define SL_LS2K1000_EX      0   /* [可配置] */
// /* 环境是否为平台 */
// #define SL_RM48_EX          0   /* [可配置] */
// /* 环境是否为WIN */
// #define SL_WIN_EX           1   /* [可配置] */

// /* 环境检查 */
// #if ((SL_LS2K1000_EX + SL_RM48_EX + SL_WIN_EX ) != 1)
// #error make sure just choose one env of sline ?
// #if (SL_LS2K1000_EX)
// #warning you choose [ SL_LS2K1000_EX ]
// #endif
// #if (SL_RM48_EX)
// #warning you choose [ SL_RM48_EX ]
// #endif
// #if (SL_WIN_EX)
// #warning you choose [ SL_WIN_EX ]
// #endif
// #endif

/* 是否使用打印开头 */
// #define SL_START_PRINT      2           /* [可配置] */
/* 对外api */
#define SL_API              extern
/* 输入字符头 */
// #define SL_HEADER			"sline>"    /* [可配置] */
/* 命令行版本 */
/* v1.1.5 - 2023.11.28   公共字段联想，ymodem组件加入 */
/* v1.1.4 - 2023.10.31   新增外部api，加入Lua环境 */
/* v1.1.3 - 2023.10.10   新增关键字添加、tap联想功能 */
/* v1.1.2 - 2023.9.20    新增平台适配 */
/* v1.1.1 - 2023.5.18    修复在历史记录切换时，填充buff为空格的问题
                         增加函数调用的预制指令 sl_cmd_export_pre */
/* v1.1.0 - 2023.5.5     实现的历史记录，命令补全，预制命令等功能 */
/* v1.0.0 - ?.?.?        只实现了指令注册等基本的简单功能 */
#define SL_VERSION 			"1.1.5"

/* 缓冲区的长度和个数，同时决定单个指令最大长度 */
#define SL_HIS_FIFO_LEN     256
#define SL_HIS_FIFO_NUM     10
/* 打印缓冲区长度 */
#define SL_PRINTF_NUM       1024
/* cmds的长度 */
#define SL_CMDS_LEN         40
/* 支持指令最大参数量 */
#define SL_CMD_ARGC_MAX     10
/* 命令名字长度 */
#define SL_CMD_NAME_LEN     32
/* 命令描述长度 */
#define SL_CMD_DESC_LEN     128
/* 关键字最大提示数量 */
#define SL_NOTICE_NUM       5
/* 关键字的启用、长度和个数 */
// #define SL_KEYWORD_ENABLE   1       /* [可配置] */
// #define SL_KEYWORD_LEN      32
// #define SL_KEYWORD_NUM      64
// /* 是否采用外部接口接管 */
// #define SL_OUTPUT_ENABLE    1       /* [可配置] */

/**
 * @brief 关键字对象结构体
 * 
 * @param keys 关键字
 * @param num  数量
 */
typedef struct 
{
    char keys[SL_KEYWORD_NUM][SL_KEYWORD_LEN];
    int num;
}sl_keys_st;

/**
 * @brief 命令的对象结构体
 * 
 * @param name 名字
 * @param func 指令函数指针
 * @param desc 指令目的
 */
typedef struct 
{
    const char name[SL_CMD_NAME_LEN];
    int (*func)(int argc,char *argv[]);
    const char desc[SL_CMD_DESC_LEN];
}sline_cmd_t;

/**
 * @brief 代码段命令的对象结构体
 * 
 * @param name 名字
 * @param func 指令函数指针
 * @param desc 指令目的
 */
typedef struct 
{
    const char * name;
    int (*func)(int argc,char *argv[]);
    const char * desc;
}sline_cmd_code_t;

#if (SL_LS2K1000_EX)
/**
 * @brief 注册指令到代码段中
 * 
 */
#define SL_CMD_EXPORT(func,desc)                                        \
        const char sline_cmd_name##func[] = #func;                      \
        const char sline_cmd_desc##func[] = #desc;                      \
        __attribute__((used)) const sline_cmd_code_t sline_cmd_t_##func \
        __attribute__((section("cmd_list")))= {                         \
        sline_cmd_name##func,                                           \
        (func),                                                         \
        sline_cmd_desc##func                                            \
        };

#endif

/**
 * @brief 注册sline对象所需要的字符收发函数
 *          这部分接口更为与标准C一致
 */
typedef struct 
{
    /*int 为getc的返回值-1 为失败 其余为获得的值,裸机中必须配置为非阻塞的*/
    int (*getc) (void); 
    /*int 为putc的返回值-1 为失败 其余为输出的值 char为输出值*/
    int (*putc) (char); 
}sl_register_func_t;

/**
 * @brief 当前显示数据结构体
 * 
 */
typedef struct
{
    char buff[SL_HIS_FIFO_LEN];
    int  len;
}sl_dis_t;

/**
 * @brief sline对象的环境结构体
 * 
 */
typedef struct
{
    int status;                       /*sl的状态,0表示启用,非0表示不启用*/
    sl_register_func_t func;          /*当前的注册函数*/
    sl_dis_t dis;                     /*显示指令储存*/
    unsigned int dis_cursor;          /*显示光标位置*/
    sl_dis_t his[SL_HIS_FIFO_NUM];    /*历史指令fifo*/
    unsigned int his_cursor;          /*历史光标位置*/
    unsigned int wkey_val;            /*记录多字符按键值*/
}sl_env_t;

#if (SL_OUTPUT_ENABLE)
/**
 * @brief sline外部调用接口
 * 
 */
typedef struct 
{
    int flag;                       /* 设置flag 0<则放弃接管 ≥0启用外部接管 */
    int (*output)(char * str);      /* 移交输入的外部接口 */
}sl_output_t;
#endif

/*创建sline对象*/
SL_API int sl_create(sl_register_func_t * sl_rfunc);
/*关闭sline对象*/
SL_API void sl_delete(void);
/*等待处理命令输入*/
SL_API int sl_waitcmd (void);
/*组件打印函数*/
SL_API int sl_printf(const char *format,...);
/*在函数内注册指令*/
SL_API int sl_cmd_export_pre(char* name,void * func,char *desc);

#if (SL_OUTPUT_ENABLE)
/* 设置是否移交输入至外部接口 */
SL_API int sl_output_set(sl_output_t * op);
#endif

#if(SL_KEYWORD_ENABLE)
/*添加单个关键字*/
SL_API int sl_key_add(char * key);
/*添加多个关键字*/
SL_API int sl_keys_add(char **keys, int num);
#endif

#ifdef __cplusplus
}
#endif

#endif /*__SLINE_H__*/
